// Copyright (c) [2019] [huazhonghua]
// [理解] is licensed under the Mulan PSL v1.
// You can use this software according to the terms and conditions of the Mulan PSL v1.
// You may obtain a copy of Mulan PSL v1 at:
//     http://license.coscl.org.cn/MulanPSL
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v1 for more details.

#ifndef STRUCTURE_H
#define STRUCTURE_H

#include <stdlib.h>
#include <wchar.h>

#include "labels.h"

typedef struct Table Table;

union Other {
	void* pointer;
	char c_char;
	int c_int;
	wchar_t c_wchar_t;
};

typedef union Other Other;

struct Node {
	int part;
	Table* table;
	Other other;
};

typedef struct Node Node;

struct List {
	int length;
	int capacity;
	Node** nodes;
};

typedef struct List List;

Node* create_node_only();

List* create_list(int capacity);

void free_list(List* list);

void clear_list(List* list);

void add_to_list(List* list, Node* node);

Node* get_list_tail(List* list);

Node* get_list_node_tail(Node* node);

Node* get_list_node_head(Node* node);

struct Link {
	int part;
	Node* target;
};

typedef struct Link Link;

struct Bucket {
	int length;
	int capacity;
	Link** links;
};

typedef struct Bucket Bucket;

Bucket* create_bucket();

int find_link_in_bucket(Bucket* bucket, int part);

int set_bucket_link(Bucket* bucket, Link* link);

struct Table {
	unsigned link_count;
	unsigned buckets_size;
	Bucket** buckets;
};

Table* create_table();

Bucket* get_part_bucket(Table* table, int part);

Link* get_table_link(Table* table, int part);

void remove_table_link(Table* table, int part);

Node* get_table_node(Table* table, int part);

Node* get_table_node_by_parts(Table* table, int* parts, int parts_length);

Node* get_node_by_parts(Node* node, int* parts, int parts_length);

Node* get_chained(Node* node, int* parts, int parts_length);

Node* get_node_by_part_list(Node* node, List* part_list);

Node* get_linked(Node* node, int part);

int is_overloaded(int link_count, int buckets_size);

int set_buckets_link(Bucket** buckets, int buckets_size, Link* link);

void resize_table(Table* table);

void set_table_node(Table* table, int part, Node* node);

void link_node(Node* node, int part, Node* target);

void unlink_node(Node* node, int part);

void make_list_node(Node* all, Node* node, int capacity);

Node* create_list_node(Node* all, int capacity);

Node* get_create_part_node(Node* all, Node* node, int part);

Node* get_create_node(Node* all, Node* node, int* parts, int parts_length);

void set_node(Node* node, int path, Node* target);

int get_next_instance_part(Node* instances);

Node* create_instance(Node* all, Node* type);

void add_to_list_node(Node* list_node, Node* node);

Node* get_list_node_item(Node* list_node, int i);

void set_list_node_item(Node* list_node, int index, Node* node);

int get_list_node_length(Node* list_node);

Node* clear_list_node(Node* list_node);

void free_bucket(Bucket* bucket);

void free_table(Table* table);

void free_node(Node* node);

void free_node_and_other(Node* node);

void free_list_node(Node* node);

int get_link_count(Node* node);

void iterate_links(Node* node, int (*handle_link)(void* state, Link* link), void* state);

void iterate_linked(Node* node, int (*handle_node)(void* state, Node* node), void* state);

Node* create_track_node(Node* all);

Node* create_node_no_track(Node* all);

Node* (*create_node)(Node*);

#endif
